package graphdisplay;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * @author Jeremy Mikkola
 */
public class Display extends JFrame {

    public Display(Graph graph) {
        setTitle("Graph display");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(new GraphPanel(graph));
        pack();
        setResizable(false);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private class GraphPanel extends JPanel {

        private Graph g;
        private int size;
        private Point[] points;
        private static final int WIDTH = 600, HEIGHT = 600, DOT_SIZE = 20;
        private int centerX, centerY, dotOffsetX, dotOffsetY;

        public GraphPanel(Graph graph) {
            g = graph;
            size = g.size();
            points = new Point[size];

            centerX = WIDTH / 2;
            centerY = HEIGHT / 2;
            dotOffsetX = centerX - DOT_SIZE / 2;
            dotOffsetY = centerY - DOT_SIZE / 2;

            setUpPoints();
            setBackground(Color.WHITE);
            setPreferredSize(new Dimension(WIDTH, HEIGHT));
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            drawEdges(g2);
            drawCliqueEdges(g2);
            drawVerticies(g2);
        }

        private void drawEdges(Graphics2D g2) {
            g2.setColor(Color.red);
            for (int i = 0; i < size; i++) {
                for (int j = i+1; j < size; j++) {
                    if (! g.get(i, j))
                        drawEdge(points[i], points[j], g2);
                }
            }
            g2.setColor(Color.blue);
            for (int i = 0; i < size; i++) {
                for (int j = i+1; j < size; j++) {
                    if (g.get(i, j))
                        drawEdge(points[i], points[j], g2);
                }
            }
        }

        private void drawCliqueEdges(Graphics2D g2) {
            g2.setColor(Color.green);
            int[] lst1 = {18, 19, 20, 40, 41};
            for (int i = 0; i < 5; i++) {
                for (int j = i+1; j < 5; j++) {
                    drawEdge(points[lst1[i]], points[lst1[j]], g2);
                }
            }
            int[] lst2 = {18, 19, 39, 40, 41};
            for (int i = 0; i < 5; i++) {
                for (int j = i+1; j < 5; j++) {
                    drawEdge(points[lst2[i]], points[lst2[j]], g2);
                }
            }

        }

        private void drawEdge(Point a, Point b, Graphics2D g2) {
            int ax = a.x + centerX,
                    bx = b.x + centerX,
                    ay = a.y + centerY,
                    by = b.y + centerY;
            g2.drawLine(ax, ay, bx, by);
        }

        private void drawVerticies(Graphics2D g2) {
            int dotColor = 100;
            g2.setColor(new Color(dotColor, dotColor, dotColor));
            for (Point p : points)
            drawPoint(p, g2);
        }

        private void drawPoint(Point p, Graphics2D g2) {
            g2.fill(new Ellipse2D.Double(p.x + dotOffsetX,
                    p.y + dotOffsetY, DOT_SIZE, DOT_SIZE));
        }

        private void setUpPoints() {
            Point p1 = new Point(0, 50 - centerY), p2;
            double angle;

            points[0] = p1;
            for (int i = 1; i < size; i++) {
                angle = 2.0 * i * Math.PI / size;
                p2 = rotatePoint(p1, angle);
                points[i] = p2;
            }
        }

        private Point rotatePoint(Point p, double angle) {
            Point out = new Point();
            double h = Math.sqrt(p.x*p.x + p.y*p.y);
            double theta = Math.atan2(p.y, p.x) + angle;
            out.setLocation(
                    h * Math.cos(theta),
                    h * Math.sin(theta));
            return out;
        }

    }

}
